package algorytm;
import java.util.Comparator;
import java.util.Random;
import java.lang.*;

import edu.uci.ics.jung.graph.Graph;

public class Chromosom {
	private boolean[] gens;
	private int size;				//liczba wezlow calego grafu
	private int vertexAmount;		//liczba wezlow w podgrafie-osobniku
	private int edgeAmount;
	private int edges2Clique;
	private double adjustment;
	private double probability;
	
	Chromosom()	{}
	
	Chromosom(int size) {
		this.size=size;
		gens=new boolean[size];
		this.fillRandom();
	}
		
	public void fillRandom() 
	{
		vertexAmount=0;
		Random r=new Random();
		for (int i=0; i<size; ++i)
		{
			gens[i]=r.nextBoolean();
			if (gens[i]==true)
				++vertexAmount;		
		}
	}
	
	public int countEdges2Clique()
	{
		System.out.println("w countEdgeToClique" + edgeAmount + "po countEdgeToClique");
		
		edges2Clique=vertexAmount*(vertexAmount-1)/2-edgeAmount;			
		return edges2Clique;
	}
	
	public void mutate(double probability) //probability in (0, 1)
	{
		Random r=new Random();
		
		for (int i=0; i<size; ++i)
		{
			if (r.nextDouble()<probability)
			{
				if (this.gens[i]==true)
				{
					this.gens[i]=false;
					--vertexAmount;
				}
				else
				{
					this.gens[i]=true;
					++vertexAmount;
				}
			}			
		}
	}
	
	public void crossoverOneChildSinglePoint(Chromosom father, Chromosom mother)				//modyfikuje ten chromosom tak by byl on wynikime skrzyzowania chromosomow podanych jako parametry
	{
		vertexAmount=0;
		Random r=new Random();
		int slice=r.nextInt(father.getSize());
		this.size=father.getSize();
		this.gens=new boolean[this.size];
		for (int i=0; i<slice; ++i)
		{
			this.gens[i]=father.getGen(i);
			if (this.gens[i]==true)
				++vertexAmount;
		}
		for (int i=slice; i<size; ++i)
		{
			this.gens[i]=mother.getGen(i);
			if (this.gens[i]==true)
				++vertexAmount;
		}
	}
	
	public void crossoverOneChildMultiPoint(Chromosom father, Chromosom mother)
	{
		vertexAmount=0;
		Random r=new Random();
		this.size=father.getSize();
		this.gens=new boolean[this.size];
		for (int i=0; i<size; ++i)
		{
			if (r.nextBoolean()==true) 
			{
				this.gens[i]=father.getGen(i);
				if (this.gens[i]==true)
					++vertexAmount;
			}
			else
			{
				this.gens[i]=mother.getGen(i);
				if (this.gens[i]==true)
					++vertexAmount;
			}
		}
	}
	
	public int countEdges(Graph g)
	{
		edgeAmount=0;
		for (int i=0; i<size; ++i)
		{
			if (gens[i]==true)
			{
				for (int j=0; j<size; ++j)
				{
					if (gens[j]==true)
					{
						Object edge=g.findEdge(i, j); 
						if (edge!= null)
							++edgeAmount;
					}
				}
			}
		}
		edgeAmount/=2;
		return edgeAmount;
	}
	
	public boolean[] getGens()
	{
		return gens;
	}
	
	public boolean getGen(int position)
	{
		return gens[position];
	}
	
	public int getSize()
	{
		return size;
	}
	
	public double getAdjustment()
	{
		return adjustment;
	}
	
	public double getProbability() {
		return this.probability;
	}
	
	
	//TODO adjustment wychodzi ujemny
	public void countAdjustment(Graph g)
	{
		System.out.println("w countAdj");
		System.out.println(g.getEdgeCount());
		System.out.println(this.countEdges2Clique());
		System.out.println(this.vertexAmount);
		System.out.println(this.countPremium());
		System.out.println("po countAdj");
		adjustment=g.getEdgeCount()-this.countEdges2Clique()+this.vertexAmount*this.countPremium();				//spec. dla danej implementacji?? 
		
		adjustment = Math.abs(adjustment);				//TODO tmp
	}

	private double countPremium() {
		if (this.edges2Clique==0)
			return 1;
		else
			return 1/(edges2Clique+1);
	}
	
	
	public void countProbability(double sum) {			//prawdopodobieństwo jest zarazem procentem wycinka koła, w alg. selekcji ruletkowej
		this.probability = this.adjustment / sum;		
		
	}
	
	private String toStringGens() {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for (boolean b : gens) {
			if (b) {
				sb.append(1);
			} else {
				sb.append(0);
			}
		}
		return sb.toString();
		
	}
	
	public String toString() {					//example: 100000001001100   15   4   0   6   8.0   0.0
		StringBuilder sb = new StringBuilder();
		
		sb.append("hasCode:_").append(this.hashCode()).append("_konHsh").append(toStringGens()).append("   ").append(this.size).append("   ").append(this.vertexAmount).append("   ")
		  .append(this.edgeAmount).append("   ").append(this.edges2Clique).append("   aaa").append(this.adjustment)
		  .append("aaa   ").append(this.probability);
		
		return sb.toString();
	}
}

class AdjustmentComparator implements Comparator<Chromosom>
{
	public int compare(Chromosom first, Chromosom second) 
	{
		if (((Chromosom) first).getAdjustment()>((Chromosom) second).getAdjustment())
			return 1;
		else if (((Chromosom) first).getAdjustment()==((Chromosom) second).getAdjustment())
			return 0;
		else return -1;
	}
}		

class ProbabilityComparator implements Comparator<Chromosom>
{
	@Override
	public int compare(Chromosom lc, Chromosom rc) 
	{
		if (lc.getProbability() > rc.getProbability())
			return 1;
		if (lc.getProbability() == rc.getProbability())
			return 0;
		return -1;
	}
}
